package main.java.com.waylau.netty.demo.protocol;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

/**
 * 说明：
 *
 * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月11日
 * 基于长度的拆包
 * 每次只拆一个数据包
 */
public class ProtocolDecoder extends LengthFieldBasedFrameDecoder {
	private static final int HEADER_SIZE = 10;

	private byte magic; // 魔数
	private byte msgType; // 消息类型
	private short reserve; // 保留字
	private short sn; // 序列号
	private int len; // 长度
 
	/**
	 * @param maxFrameLength
	 * @param lengthFieldOffset
	 * @param lengthFieldLength
	 * @param lengthAdjustment
	 * @param initialBytesToStrip
	 */
	public ProtocolDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
		super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip);
 	}

	/**
	 * @param maxFrameLength
	 * @param lengthFieldOffset
	 * @param lengthFieldLength
	 * @param lengthAdjustment
	 * @param initialBytesToStrip
	 * @param failFast
	 */
	public ProtocolDecoder(int maxFrameLength, int lengthFieldOffset,
			int lengthFieldLength, int lengthAdjustment,
			int initialBytesToStrip, boolean failFast) {
		super(maxFrameLength, lengthFieldOffset, lengthFieldLength,
				lengthAdjustment, initialBytesToStrip, failFast);
	}


	/**
	 * LengthFieldBasedFrameDecoder 已经帮忙拆好包了
	 * 这里负责将拆好的数据包解码
	 */
	@Override
	protected ProtocolMsg decode(ChannelHandlerContext ctx, ByteBuf in2) throws Exception {
		ByteBuf in = (ByteBuf) super.decode(ctx, in2);
		if (in == null) {
		    return null;// 知道读出完整的数据帧
		}

		// 这里 刚好是那个offset
		// 这个头部长度是由 构造器中的参数决定的
		if (in.readableBytes() < HEADER_SIZE) {
			return null;
		}

		// 这读出来的是头部 buff的指针会向后移动
		magic = in.readByte();//1
		msgType = in.readByte();//1
		reserve = in.readShort();//2
		sn = in.readShort();//2 ++=6个 字节偏移
		len = in.readInt();//4 长度域 用于保存数据长度


		// 这里读出来的是内容长度
		if (in.readableBytes() < len) {
			return null; // until we have the entire payload return
		}

		// 新建一个内容实体：只有内容长度的
		ByteBuf buf = in.readBytes(len);
		byte[] req = new byte[buf.readableBytes()];// 到这里后28个字节全部读完了
		buf.readBytes(req);// 取出实体内容 这里只有18 个字节是长度
		String body = new String(req, "UTF-8");
		ProtocolMsg msg = new ProtocolMsg();//封装成一个数据包：包含头部，类型，保留字
		ProtocolHeader protocolHeader = new ProtocolHeader(magic, msgType, reserve, sn, len);
		msg.setBody(body);
		msg.setProtocolHeader(protocolHeader);
		return msg;
	}
}
